﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing.Design;


namespace TR0217.ControlEx
{
    [ToolboxBitmap(typeof(CheckedListBox))]
    public class CheckComboBox:ComboBox
    {
        CheckedListBox _chkLisBox;
        ContextContainer _ctxContainer;

        private char _separatorChar = ',';
        public char SeparatorChar
        {
            get { return _separatorChar; }
            set { _separatorChar = value; }
        }

        public bool GetItemChecked(int index)
        {
            if (index < 0 || index > Items.Count)
            {
                throw new ArgumentOutOfRangeException("index", "value out of range");
            }
            else
            {
                return _chkLisBox.GetItemChecked(index);
            }
        }

        public void SetItemChecked(int index, bool isChecked)
        {
            if (index < 0 || index > Items.Count)
            {
                throw new ArgumentOutOfRangeException("index", "value out of range");
            }
            else
            {
                _chkLisBox.SetItemChecked(index, isChecked);
                // Need to update the Text.
                this.Text = this.GetCheckedItemsStringValue();
            }
        }

        public CheckState GetItemCheckState(int index)
        {
            if (index < 0 || index > Items.Count)
            {
                throw new ArgumentOutOfRangeException("index", "value out of range");
            }
            else
            {
                return _chkLisBox.GetItemCheckState(index);
            }
        }

        public void SetItemCheckState(int index, CheckState state)
        {
            if (index < 0 || index > Items.Count)
            {
                throw new ArgumentOutOfRangeException("index", "value out of range");
            }
            else
            {
                _chkLisBox.SetItemCheckState(index, state);
                // Need to update the Text.
                this.Text = this.GetCheckedItemsStringValue();
            }
        }

        private string GetCheckedItemsStringValue()
        {
            StringBuilder sb = new StringBuilder("");
            for (int i = 0; i < _chkLisBox.CheckedItems.Count; i++)
            {
                sb.Append(_chkLisBox.GetItemText(_chkLisBox.CheckedItems[i])).Append(this.SeparatorChar);
            }
            if (sb.Length > 0)
            {
                sb.Remove(sb.Length - 1, 1);
            }
            return sb.ToString();
        }

        public bool CheckOnClick
        {
            get { return _chkLisBox.CheckOnClick; }
            set { _chkLisBox.CheckOnClick = value; }
        }

        public new string DisplayMember
        {
            get { return _chkLisBox.DisplayMember; }
            set { _chkLisBox.DisplayMember = value; }
        }

        public new int DropDownHeight
        {
            get { return _ctxContainer.DropDownHeight; }
            set { _ctxContainer.DropDownHeight = value; }
        }

        public new int DropDownWidth
        {
            get { return _ctxContainer.DropDownWidth; }
            set 
            {
                base.DropDownWidth = value;
                _ctxContainer.DropDownWidth = value; 
            }
        }

        [Editor("System.Windows.Forms.Design.ListControlStringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public new CheckedListBox.ObjectCollection Items
        {
            get { return _chkLisBox.Items; }
        }
        
        [Browsable(false)]
        public CheckedListBox.CheckedItemCollection CheckedItems
        {
            get { return _chkLisBox.CheckedItems; }
        }

        [Browsable(false)]
        public CheckedListBox.CheckedIndexCollection CheckedIndices
        {
            get { return _chkLisBox.CheckedIndices; }
        }

        public CheckComboBox()
        {
            _chkLisBox = new CheckedListBox();

            _chkLisBox.BorderStyle = BorderStyle.None;
            _chkLisBox.SelectionMode = SelectionMode.One;
            _chkLisBox.HorizontalScrollbar = true;
            _chkLisBox.CheckOnClick = true;

            _ctxContainer = new ContextContainer(_chkLisBox);
            _ctxContainer.FocusOnOpen = true;
            _ctxContainer.DropDownAssistant.AutoSize = false;
            _ctxContainer.ContextMode = ContextMode.MultiSelect;
            _ctxContainer.Resizable = true;
            _ctxContainer.Closed += new ToolStripDropDownClosedEventHandler(_ctxContainer_Closed);
            base.DropDownStyle = ComboBoxStyle.DropDown;
            base.DropDownHeight = 1;
        }

        void _ctxContainer_Closed(object sender, ToolStripDropDownClosedEventArgs e)
        {
            base.OnDropDownClosed(e);
            this.Text = GetCheckedItemsStringValue();
        }

        public new ComboBoxStyle DropDownStyle
        {
            get
            {
                return base.DropDownStyle;
            }
            set
            {
                if (value != ComboBoxStyle.DropDown)
                {
                    throw new NotSupportedException("ComboBoxStyle.DropDown is the only supported style");
                }
                base.DropDownStyle = value;
            }
        }

        protected override void OnDropDown(EventArgs e)
        {
            base.OnDropDown(e);
            _ctxContainer.Show(this);
        }

        protected override void OnDropDownClosed(EventArgs e)
        {
            return;
        }
        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Down)
            {
                // Signal that the dropdown is "down". This is required so that the behaviour of the dropdown is the same
                // when it is a result of user pressing the Down_Arrow (which we handle and the framework wouldn't know that
                // the list portion is down unless we tell it so).
                // NOTE: all that so the DropDownClosed event fires correctly!                
                _ctxContainer.Show(this);
            }
            // Make sure that certain keys or combinations are not blocked.
            e.Handled = !e.Alt && !(e.KeyCode == Keys.Tab) &&
                !((e.KeyCode == Keys.Left) || (e.KeyCode == Keys.Right) || (e.KeyCode == Keys.Home) || (e.KeyCode == Keys.End));

            base.OnKeyDown(e);
        }

        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            e.Handled = true;
            base.OnKeyPress(e);
        }

        protected override void Dispose(bool disposing)
        {
            if (!base.IsDisposed)
            {
                _chkLisBox.Dispose();
                _ctxContainer.Dispose();
                base.Dispose(disposing);
            }
        }
    }
}
